package com.ebupt.migu.music.userGroup.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.Cursor;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.ebupt.migu.common.pojo.CustomerFileBean;
import com.ebupt.migu.common.pojo.CustomerMergeRequestBean;
import com.ebupt.migu.common.pojo.CustomerStatusRequestBean;
import com.ebupt.migu.common.pojo.ValidRequestBean;
import com.ebupt.migu.music.common.constants.UserGroupConstants;
import com.ebupt.migu.music.common.entity.Page;
import com.ebupt.migu.music.common.entity.ResultObject;
import com.ebupt.migu.music.common.exception.MyException;
import com.ebupt.migu.music.common.exception.StatusEnum;
import com.ebupt.migu.music.common.util.DateUtil;
import com.ebupt.migu.music.common.util.ExportFileDataFromRedis;
import com.ebupt.migu.music.label.utils.SftpUtils;
import com.ebupt.migu.music.redis.service.RedisService;
import com.ebupt.migu.music.system.entity.SysUser;
import com.ebupt.migu.music.system.mapper.RoleMapper;
import com.ebupt.migu.music.userGroup.entity.AttributeBean;
import com.ebupt.migu.music.userGroup.entity.UserGroupInfo;
import com.ebupt.migu.music.userGroup.entity.dto.UserGroupDTO;
import com.ebupt.migu.music.userGroup.entity.vo.UserGroupVo;
import com.ebupt.migu.music.userGroup.mapper.CrowdMapper;
import com.ebupt.migu.music.userGroup.service.CrowdListService;
import com.ebupt.migu.music.userGroup.util.ThreadPools;
import com.ebupt.migu.restapi.RestHttpPost;

import freemarker.template.Configuration;
import lombok.extern.slf4j.Slf4j;

/**
 * Created by Intellij IDEA. User: liuyangyang@cd.ebupt.com Date: 2019/9/13
 */

@Slf4j
@Service
public class CrowdListServiceImpl implements CrowdListService {

    @Autowired
    private CrowdMapper crowdMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private LabelServiceImpl labelServiceImpl;
    @Autowired
    Configuration configuration;
    @Autowired
    SftpUtils sftpUtils;
    @Autowired
    ExportFileDataFromRedis exportFileDataFromRedis;
    @Resource
    RedisService redisService;

    @Value("${label.prefix}")
    private String LABEL_PREFIX;
    @Value("${label.customer_valid}")
    private String CUSTOMER_VALID;
    @Value("${label.customer_merge}")
    private String CUSTOMER_MERGE;
    @Value("${label.customer_status}")
    private String CUSTOMER_STATUS;
    @Value("${label.customer_insight}")
    private String customerInsight;
    private String REDIS_COUNT_NAME = "COUNT_BY_DAY";
    /**
     * 每日最多洞察次数
     */
    private static final int MAX_INSIGHT_TIMES = 20;

    /**
     * 手动更新人群
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject refreshCrowd(Map<String, Object> params) {
        if (null == params.get("groupId") || StringUtils.isBlank(params.get("groupId").toString())) {
            throw new MyException(StatusEnum.BUSINID, "用户群ID不可为空！");
        }
        // 用户群ID
        String gid = params.get("groupId").toString();
        log.info("客群{}被用户手动更新", gid);
        try {
            HashMap<String, Object> map = crowdMapper.queryByGroupID(gid);
            String isStaticCustomer = String.valueOf(map.get("isStaticCustomer"));
            String isDynamicCustomer = String.valueOf(map.get("isDynamicCustomer"));
            // 用户群状态修改为待更新
            if ("1".equals(isStaticCustomer) && "0".equals(isDynamicCustomer)) {
                // 静态客群修改成更新中
                params.put("createStatus", UserGroupConstants.UPDATING);
                log.info("将客群状态更新到更新中:{}", gid);
            } else {
                // 非静态客群修改成待更新
                params.put("createStatus", UserGroupConstants.WAITING_FOR_UPDATE);
                log.info("将客群状态更新到待更新:{}", gid);
            }
            // 更新优先级设置为2-手动更新
            params.put("updatePrio", UserGroupConstants.MANUAL_UPDATE);
            customerStatus(gid, 1);
            crowdMapper.refreshCrowd(params);
        } catch (Exception e) {
            log.error("手动更新人群失败：" + gid, e);
            throw new MyException(StatusEnum.UPDATE_USER_GROUP_ERROR, "更新用户群失败");
        }
        ResultObject res = new ResultObject();
        res.setMsg("提交更新请求成功, 请等待更新完成！");
        return res;
    }

    /**
     * 更新人群信息
     * <p>
     * 2019-10-10调整： i 仅通过标签方式创建的人群可以被更新 ii 参与了人群重组的人群，不可以被更新
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject updateCrowd(Map<String, Object> params) {
        if (null == params.get("groupId") || StringUtils.isBlank(params.get("groupId").toString())) {
            throw new MyException(StatusEnum.BUSINID, "用户群ID不可为空！");
        }
        String gid = params.get("groupId").toString();
        // 查询当前人群是否参与人群重组
        List<HashMap<String, Object>> infos = crowdMapper.queryResGroups(gid);
        List<String> gids = new ArrayList<>();
        if (!infos.isEmpty()) {
            for (Map<String, Object> info : infos) {
                // 将参与重组之后的人群名称保存下来
                gids.add(info.get("userGroupName").toString());
            }
            log.info("该用户群体已经被{}重组引用", gids.toString());
        }

        // 查询当前人群是否参与策略运营
        List<HashMap<String, Object>> strategys = crowdMapper.queryPartInStrategy(gid);
        if (!strategys.isEmpty()) {
            for (Map<String, Object> strategy : strategys) {
                // 将参与的策略名称保存下来
                gids.add(strategy.get("strategyName").toString());
            }
            log.info("该用户群体正在参与{}活动的运营", gids.toString());
        }

        try {
            int saveType = Integer.parseInt(params.get("saveType").toString());
            if (saveType == 0) {
                // 创建状态设置为保存入草稿箱
                // 默认是动态标签创建
                params.put("createWay", UserGroupConstants.CREATE_BY_DYNAMIC_LABEL);
                params.put("createStatus", UserGroupConstants.WAITING_FOR_SUBMISSION);
            } else {
                // 是否静态标签创建的人群
                if (labelServiceImpl.isDyna(params.get("groupAttribute").toString())) {
                    params.put("createWay", UserGroupConstants.CREATE_BY_DYNAMIC_LABEL);
                    params.put("createStatus", UserGroupConstants.BEING_CREATED);
                } else {
                    params.put("createWay", UserGroupConstants.CREATE_BY_STATIC_LABEL);
                    params.put("createStatus", UserGroupConstants.BEING_CREATED);
                }
            }
            // log.info("上报重组客群");
            // recombineCustomerPerHandel(params);
            ValidRequestBean validRequestBean = new ValidRequestBean();
            validRequestBean.setCustomerId(gid);
            validRequestBean.setStatus(1);
            validRequestBean.setIsDynamic(Integer.valueOf(String.valueOf(params.get("isDynamicCustomer"))));
            RestHttpPost post = new RestHttpPost();
            post.doRest(validRequestBean, LABEL_PREFIX + CUSTOMER_VALID);
            crowdMapper.updateCrowd(params);

            // 在hive_delay_update表创建记录
            hiveDelayUpdate(gid, params.get("groupAttribute").toString());
        } catch (Exception e) {
            log.error("更新人群信息失败：" + params.get("groupId").toString(), e);
            throw new MyException(StatusEnum.UPDATE_USER_GROUP_ERROR, "更新用户群信息失败");
        }
        ResultObject res = new ResultObject();
        res.setMsg("更新成功！");
        return res;
    }

    /**
     * 删除人群 1. groupId在resGroups中存在 2. createStatus ！= 8 （不是删除状态） 3. 策略状态不可被标记为： 1-待审核；2-已驳回；3-未开始；4-进行中； 4. i.
     * WEB先弹出确认删除提示，确定之后发请求 ii. 查询人群是否参与重组 iii. 查询人群是否存在运营策略
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject deleteCrowd(Map<String, Object> params) {
        ResultObject res = new ResultObject();
        if (null == params.get("groupId") || StringUtils.isBlank(params.get("groupId").toString())) {
            throw new MyException(StatusEnum.BUSINID, "用户群ID不可为空！");
        }
        String gid = params.get("groupId").toString();
        // 查询当前人群是否参与人群重组
        List<HashMap<String, Object>> infos = crowdMapper.queryResGroups(gid);
        List<String> gids = new ArrayList<>();
        if (!infos.isEmpty()) {
            for (Map<String, Object> info : infos) {
                // 将参与重组之后的人群名称保存下来
                gids.add(info.get("userGroupName").toString());
            }
            res.setCode(StatusEnum.PART_IN_RECOMBINE.getCode());
            res.setMsg("该用户群体已被" + gids.toString() + "重组引用，请先删除该用户群，再进行删除。");
            return res;
            // throw new PromptException(StatusEnum.PART_IN_RECOMBINE, "该用户群体已被" + gids.toString() +
            // "重组引用，请先删除该用户群，再进行删除。");
        }
        // 查询当前人群是否参与策略运营
        List<HashMap<String, Object>> strategys = crowdMapper.queryPartInStrategy(gid);
        if (!strategys.isEmpty()) {
            for (Map<String, Object> strategy : strategys) {
                // 将参与的策略名称保存下来
                gids.add(strategy.get("strategyName").toString());
            }
            res.setCode(StatusEnum.PART_IN_OPERATE.getCode());
            res.setMsg("该用户群体正在参与" + gids.toString() + "活动的运营，暂不能删除。");
            return res;
            // throw new PromptException(StatusEnum.PART_IN_OPERATE, "该用户群体正在参与" + gids.toString() + "活动的运营，暂不能删除。");
        }
        // 未参与人群重组且未参与策略运营的人群才可以被删除
        try {
            params.put("createStatus", UserGroupConstants.DELETED);
            crowdMapper.updateCrowd(params);
        } catch (Exception e) {
            log.error("删除人群失败：" + gid, e);
            throw new MyException(StatusEnum.DELETE_USER_GROUP_ERROR, "删除人群失败！");
        }

        // 上报客群删除
        customerStatus(gid, 9);
        res.setMsg("删除成功！");
        return res;
    }

    /**
     * 重组方式创建人群
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject addCrowd(Map<String, Object> params) {
        String yyyyMMddHHmmss = DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS);
        // 请求参数必须包含 createStatus
        if (params.get("createStatus") == null) {
            throw new MyException(StatusEnum.BUSINID, "createStatus不可为空！");
        }
        String createStatus = params.get("createStatus").toString();
        // createStatus：1-创建中；2-待提交（草稿箱）；
        if (StringUtils.isBlank(createStatus) || (!"1".equals(createStatus) && !"2".equals(createStatus))) {
            throw new MyException(StatusEnum.BUSINID, "createStatus参数异常！");
        }
        if ("2".equals(createStatus)) {
            try {
                crowdMapper.createUserGroup(params);
            } catch (Exception e) {
                log.error("创建人群失败：" + params.toString(), e);
                throw new MyException(StatusEnum.UPDATE_USER_GROUP_ERROR, "创建用户群信息失败");
            }
            ResultObject<String> res = new ResultObject<>();
            res.setMsg("创建成功！");
            return res;
        }
        // 请求参数必须包含createWay字段
        if (params.get("createBy") == null) {
            throw new MyException(StatusEnum.BUSINID, "createBy不可为空！");
        }
        String createBy = params.get("createBy").toString();
        // createBy断定用户群类型 1-静态条件创建；2-动态条件创建；3-文件导入创建；4-交集创建；5-并集创建；6-左差集创建；7-右差集创建；8-对称差集创建；
        if (StringUtils.isBlank(createBy)) {
            throw new MyException(StatusEnum.BUSINID, "createBy参数异常！");
        }
        // 请求参数必须包含 userGroupName字段
        if (params.get("userGroupName") == null) {
            throw new MyException(StatusEnum.BUSINID, "userGroupName不可为空！");
        }
        String userGroupName = params.get("userGroupName").toString();
        if (StringUtils.isBlank(userGroupName)) {
            throw new MyException(StatusEnum.BUSINID, "userGroupName参数异常！");
        }
        // 判断人群名称是否存被占用
        Map<String, Object> map = new HashMap<>();
        map.put("userGroupName", userGroupName);
        if (crowdMapper.isUserGroupNameExistCnt(map) > 0) {
            throw new MyException(StatusEnum.NAME_ALREADY_EXIST, "人群名称被占用，请尝试换一个人群名称！");
        }

        // 断定用户群类型 1-静态条件创建；2-动态条件创建；3-文件导入创建；4-交集创建；5-并集创建；6-左差集创建；7-右差集创建；8-对称差集创建；
        if ("4".equals(createBy) || "5".equals(createBy) || "6".equals(createBy) || "7".equals(createBy)
            || "8".equals(createBy)) {
            // 请求参数必须包含 resGroups
            if (params.get("resGroups") == null) {
                throw new MyException(StatusEnum.BUSINID, "resGroups不可为空！");
            }
            String resGroups = params.get("resGroups").toString();
            if (StringUtils.isBlank(resGroups) || !resGroups.contains(",")) {
                throw new MyException(StatusEnum.BUSINID, "resGroups参数异常！");
            }
            // 处理类型
            String groupId = "CZ" + yyyyMMddHHmmss;
            params.put("createWay", createBy);
            params.put("groupId", groupId);
            try {
                log.info("创建重组记录");
                crowdMapper.createUserGroup(params);
                // 将包含静态规则的重组客群上报至统一标签服务平台
                log.info("上报重组客群");
                recombineCustomerPerHandel(params);
            } catch (Exception e) {
                log.error("创建人群失败：" + params.toString(), e);
                throw new MyException(StatusEnum.CREATE_USER_GROUP_ERROR, "创建用户群信息失败");
            }
        } else {
            throw new MyException(StatusEnum.CREATE_USER_GROUP_ERROR, "创建用户群信息失败");
        }
        ResultObject<String> res = new ResultObject<>();
        res.setMsg("创建成功！");
        return res;
    }

    /**
     * 分页、查询人群列表 业务逻辑 1. 查询条件：1.人群名称 2.创建人 3.创建时间 4.创建形式 5.状态 6.部门 2. tags：1. 已建人群 2.草稿箱 3. 超级管理员可以查看操作所有部门所创建的人群 4.
     * 谁创建、谁更新、谁修改、谁删除 5. 可以查看本部门创建的用户群，操作仅可以引用，引用范围限定于权限范围中，比如该用户仅有短信营销的权限，则在引用时，仅能短信营销 6. 排序方式：按照创建时间降序排
     * <p>
     * 需求变更 1. “已失效”不再是一种创建状态，已失效的人群仅将自动更新变更为手动更新，其他权限范围和手动更新人群相同【2019-09-27】
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject crowdList(Map<String, Object> params, SysUser user) {
        // 请求参数必须包含tags字段
        if (params.get("tags") == null) {
            throw new MyException(StatusEnum.BUSINID, "tags不可为空！");
        }
        String tags = params.get("tags").toString();
        // tags：1-查询已建人群； 2-查询草稿箱；
        if (StringUtils.isBlank(tags) || (!"1".equals(tags) && !"2".equals(tags))) {
            throw new MyException(StatusEnum.BUSINID, "tags参数异常！");
        }
        String smsOnly = params.get("smsOnly").toString();
        // smsOnly： 1- 查询全量人群； 2- 不查询短信运营的人群
        if (StringUtils.isBlank(smsOnly) || (!"1".equals(smsOnly) && !"2".equals(smsOnly))) {
            throw new MyException(StatusEnum.BUSINID, "tags参数异常！");
        }
        // 超级管理员和全量人群管理员可以查询所有人群， 非超级管理员仅能查询本部门人群
        params = isAdmin(params, user);
        // 创建形式 1- 标签创建； 2- 文件上传创建； 3- 重组创建；
        if (params.get("createBy") != null && !"".equals(params.get("createBy").toString())) {
            String createBy = params.get("createBy").toString();
            // 默认排除FTP同步创建的人群
            params.put("isFtp", UserGroupConstants.IS_NOT_FTP);
            if ("1".equals(createBy)) {
                // 标签创建：1-静态条件创建；2-动态条件创建；
                byte[] createWay =
                    {UserGroupConstants.CREATE_BY_STATIC_LABEL, UserGroupConstants.CREATE_BY_DYNAMIC_LABEL};
                params.put("createWay", createWay);
            }
            if ("2".equals(createBy)) {
                // 文件上传创建：3-文件导入创建；
                byte[] createWay = {UserGroupConstants.CREATE_BY_FILE_UPLOAD};
                params.put("createWay", createWay);
            }
            if ("3".equals(createBy)) {
                // 人群重组创建： 4-交集创建；5-并集创建；6-左差集创建；7-右差集创建；8-对称差集创建；
                byte[] createWay = {UserGroupConstants.RECOMBINE_BY_INTERSECT, UserGroupConstants.RECOMBINE_BY_UNION,
                    UserGroupConstants.RECOMBINE_BY_DIFF_LEFT, UserGroupConstants.RECOMBINE_BY_DIFF_RIGHT,
                    UserGroupConstants.RECOMBINE_BY_DIFF_SYMMETRIC};
                params.put("createWay", createWay);
            }
            if ("4".equals(createBy)) {
                // FTP同步创建：独立字段条件筛选
                params.put("isFtp", UserGroupConstants.IS_FTP);
            }
            if ("5".equals(createBy)) {
                // 重度用户创建
                byte[] createWay = {UserGroupConstants.CREATE_BY_HEAVY_USERS_LABEL};
                params.put("createWay", createWay);
            }
            if ("6".equals(createBy)) {
                // 重度用户创建
                byte[] createWay = {UserGroupConstants.CREATE_BY_USER_LIFE_CYCLE};
                params.put("createWay", createWay);
            }
            if ("7".equals(createBy)) {
                // 自动运营
                byte[] createWay = {UserGroupConstants.CREATE_BY_AutoOperate};
                params.put("createWay", createWay);
            }
            if ("8".equals(createBy)) {
                // iop标签
                byte[] createWay = {UserGroupConstants.CREATE_BY_IOP};
                params.put("createWay", createWay);
            }
        }
        // 分页查询结果集
        List<HashMap<String, Object>> datas;
        // 总数
        Integer total;
        // 分页
        Page<HashMap<String, Object>> page = new Page<>();
        ResultObject<Page<HashMap<String, Object>>> res = new ResultObject<>();
        // 查询已建人群
        if ("1".equals(tags)) {
            // 已建人群
            List<Byte> ins = new ArrayList<>();
            ins.add(UserGroupConstants.BEING_CREATED);
            ins.add(UserGroupConstants.WAITING_FOR_UPDATE);
            ins.add(UserGroupConstants.UPDATING);
            ins.add(UserGroupConstants.COMPLETED);
            ins.add(UserGroupConstants.UPDATE_FAILED);
            ins.add(UserGroupConstants.IMPORT_FAILED);
            ins.add(UserGroupConstants.LOCKING);
            log.info("create_status{}", ins);
            params.put("ins", ins);
        } else {
            // 查询草稿箱
            byte[] ins = {UserGroupConstants.WAITING_FOR_SUBMISSION};
            log.info("create_status[{}]", ins);
            params.put("ins", ins);
        }
        try {
            log.info("params:{}", params.toString());
            // 总计
            total = crowdMapper.countCrowdList(params);
            // 人群列表
            datas = crowdMapper.queryCrowdList(params);
            // 如果是重组方式创建的人群，查询参与重组的人群的名称
            for (HashMap<String, Object> data : datas) {
                if (null == data.get("createWay")) {
                    continue;
                }
                // 创建方式是否符合重组创建
                byte createWay = Byte.valueOf(data.get("createWay").toString());
                if (createWay == UserGroupConstants.RECOMBINE_BY_INTERSECT
                    || createWay == UserGroupConstants.RECOMBINE_BY_UNION
                    || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_LEFT
                    || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_RIGHT
                    || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_SYMMETRIC) {
                    // 向下查询参与重组的人群
                    String[] ids = data.get("resGroups").toString().split(",");
                    List<HashMap<String, Object>> recombines = new ArrayList<>();
                    HashMap<String, Object> recombine = new HashMap<>();
                    recombine.put("name", data.get("userGroupName"));
                    // 查询并保存参与重组的人群的名称
                    for (int i = 0; i < ids.length; i++) {
                        HashMap<String, Object> map = crowdMapper.queryByGroupID(ids[i]);
                        if (map == null) {
                            break;
                        }
                        recombine.put("group" + (i + 1), map.get("userGroupName"));
                    }
                    // 自定义命名
                    if (null == recombine.get("group1")) {
                        recombine.put("group1", "未查找到人群名称或人群已经不存在");
                        recombine.put("group2", "未查找到人群名称或人群已经不存在");
                    }
                    if (createWay == UserGroupConstants.RECOMBINE_BY_INTERSECT) {
                        recombine.put("way", "交集");
                        recombines.add(recombine);
                        data.put("recombine", recombines);
                        continue;
                    }
                    if (createWay == UserGroupConstants.RECOMBINE_BY_UNION) {
                        recombine.put("way", "并集");
                        recombines.add(recombine);
                        data.put("recombine", recombines);
                        continue;
                    }
                    if (createWay == UserGroupConstants.RECOMBINE_BY_DIFF_LEFT) {
                        recombine.put("way", "左差集");
                        recombines.add(recombine);
                        data.put("recombine", recombines);
                        continue;
                    }
                    if (createWay == UserGroupConstants.RECOMBINE_BY_DIFF_RIGHT) {
                        recombine.put("way", "右差集");
                        recombines.add(recombine);
                        data.put("recombine", recombines);
                        continue;
                    }
                    if (createWay == UserGroupConstants.RECOMBINE_BY_DIFF_SYMMETRIC) {
                        recombine.put("way", "对称差集");
                        recombines.add(recombine);
                        data.put("recombine", recombines);
                        continue;
                    }

                }
            }
        } catch (Exception e) {
            log.error("查询列表失败", e);
            throw new MyException(StatusEnum.QUERY_FAILED, "查询列表失败！");
        }
        page.setTotal(total);
        page.setData(datas);
        res.setMsg("查询人群列表成功！");
        res.setData(page);
        return res;
    }

    /**
     * 【创建策略专供】 分页、查询人群列表 业务逻辑 1. 查询条件：1.人群名称 2.创建人 3.创建时间 4.创建形式 5.状态 6.部门 2. tags：1. 已建人群 2.草稿箱 3.
     * 超级管理员可以查看操作所有部门所创建的人群 4. 谁创建、谁更新、谁修改、谁删除 5. 可以查看本部门创建的用户群，操作仅可以引用，引用范围限定于权限范围中，比如该用户仅有短信营销的权限，则在引用时，仅能短信营销 6.
     * 排序方式：按照创建时间降序排
     * <p>
     * 需求变更 1. “已失效”不再是一种创建状态，已失效的人群仅将自动更新变更为手动更新，其他权限范围和手动更新人群相同【2019-09-27】
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject liteList(Map<String, Object> params, SysUser user) {
        // 超级管理员和全量人群管理员可以查询所有人群， 非超级管理员仅能查询本部门人群
        params = isAdmin(params, user);
        ResultObject res = new ResultObject();
        // 分页
        Page<HashMap<String, Object>> page = new Page<>();
        List<HashMap<String, Object>> datas = crowdMapper.liteList(params);
        page.setTotal(0);
        page.setData(datas);
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        res.setData(page);
        return res;
    }

    /**
     * 查看参数是否包含超级管理员或全量角色管理员
     *
     * @param params 请求参数
     * @param user 用户信息
     * @return 请求参数
     */
    private Map<String, Object> isAdmin(Map<String, Object> params, SysUser user) {
        if ("0".equals(params.get("isAdmin")) && "0".equals(params.get("isFAGAdmin"))) {
            if (null == params.get("creatorDepartment") || "".equals(params.get("creatorDepartment"))) {
                params.put("creatorDepartment", user.getDeptName());
            } else if (!user.getDeptName().equals(params.get("creatorDepartment"))) {
                throw new MyException(StatusEnum.QUERY_LIMITED, "无权查看！");
            }
        }
        return params;
    }

    /**
     * 删除人群
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject deleteORupdate(Map<String, Object> params) {
        if (null == params.get("groupId") || StringUtils.isBlank(params.get("groupId").toString())) {
            throw new MyException(StatusEnum.BUSINID, "用户群ID不可为空！");
        }
        String gid = params.get("groupId").toString();
        // 查询当前人群是否参与人群重组
        List<HashMap<String, Object>> infos = crowdMapper.queryResGroups(gid);
        List<String> gids = new ArrayList<>();
        if (!infos.isEmpty()) {
            for (Map<String, Object> info : infos) {
                // 将参与重组之后的人群名称保存下来
                gids.add(info.get("userGroupName").toString());
            }
            // throw new PromptException(StatusEnum.PART_IN_RECOMBINE, "该用户群体已被" + gids.toString() +
            // "重组引用，请先删除该用户群，再进行修改或删除。");
        }
        // 查询当前人群是否参与策略运营
        List<HashMap<String, Object>> strategys = crowdMapper.queryPartInStrategy(gid);
        if (!strategys.isEmpty()) {
            for (Map<String, Object> strategy : strategys) {
                // 将参与的策略名称保存下来
                gids.add(strategy.get("strategyName").toString());
            }
            // throw new PromptException(StatusEnum.PART_IN_OPERATE, "该用户群体正在参与" + gids.toString() + "活动的运营，暂不能修改或删除。");
        }
        ResultObject res = new ResultObject();
        res.setMsg("该人群可以删除或修改");
        return res;
    }

    /**
     * 通过人群名称查询人群详情
     *
     * @param params
     * @return
     */
    @Override
    public ResultObject queryGroupDetailByName(Map<String, Object> params) {
        String userGroupName = String.valueOf(params.get("groupId"));
        Map<String, Object> data = crowdMapper.queryGroupDetailByName(userGroupName);
        // 短信审核流程修改需要将字符串转换成JSON格式
        // if (null != data.get("groupAttribute")){
        // Object groupAttribute = data.get("groupAttribute");
        // data.remove("groupAttribute");
        // data.put("groupAttribute", JSON.toJSONString(groupAttribute));
        // data.put("groupAttribute_1", JSONObject.toJSON(groupAttribute));
        // }
        ResultObject res = new ResultObject();
        if (null == data) {
            res.setCode(StatusEnum.BUSINID.getCode());
            res.setMsg("全网PUSH活动无需指定客群");
            return res;
        }
        // 创建方式是否符合重组创建
        if (null == data.get("createWay")) {
            res.setCode(StatusEnum.BUSINID.getCode());
            res.setMsg("createWay不可为空");
            return res;
        }
        byte createWay = Byte.valueOf(data.get("createWay").toString());
        if (createWay == UserGroupConstants.RECOMBINE_BY_INTERSECT || createWay == UserGroupConstants.RECOMBINE_BY_UNION
            || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_LEFT
            || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_RIGHT
            || createWay == UserGroupConstants.RECOMBINE_BY_DIFF_SYMMETRIC) {
            // 向下查询参与重组的人群
            String[] ids = data.get("resGroups").toString().split(",");
            List<HashMap<String, Object>> recombines = new ArrayList<>();
            HashMap<String, Object> recombine = new HashMap<>();

            recombine.put("name", data.get("userGroupName"));
            // 查询并保存参与重组的人群的名称
            for (int i = 0; i < ids.length; i++) {
                HashMap<String, Object> map = crowdMapper.queryByGroupID(ids[i]);
                if (map == null) {
                    break;
                }
                recombine.put("group" + (i + 1), map.get("userGroupName"));
            }
            // 自定义命名
            if (null == recombine.get("group1")) {
                recombine.put("group1", "未查找到人群名称或人群已经不存在");
                recombine.put("group2", "未查找到人群名称或人群已经不存在");
            }
            switch (createWay) {
                case UserGroupConstants.RECOMBINE_BY_INTERSECT:
                    recombine.put("way", "交集");
                    recombines.add(recombine);
                    break;
                case UserGroupConstants.RECOMBINE_BY_UNION:
                    recombine.put("way", "并集");
                    recombines.add(recombine);
                    break;
                case UserGroupConstants.RECOMBINE_BY_DIFF_LEFT:
                    recombine.put("way", "左差集");
                    recombines.add(recombine);
                    break;
                case UserGroupConstants.RECOMBINE_BY_DIFF_RIGHT:
                    recombine.put("way", "右差集");
                    recombines.add(recombine);
                    break;
                case UserGroupConstants.RECOMBINE_BY_DIFF_SYMMETRIC:
                    recombine.put("way", "对称差集");
                    recombines.add(recombine);
                    break;
            }
            data.put("recombine", recombines);
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        res.setData(data);
        return res;
    }

    @Override
    public ResultObject<List<Map<String, Object>>> queryUserGroup(Map<String, Object> params) {
        // 超级管理员可以查询所有人群， 非超级管理员仅能查询本部门人群
        if (params.get("isAdmin").equals("1")) {
            params.put("creatorDepartment", "");
        }
        List<Map<String, Object>> data = crowdMapper.queryUserGroup(params);
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), StatusEnum.SUCCESS.getMsg(), data);
    }

    @Override
    public ResultObject<List<UserGroupInfo>> queryUserGroupForInsight() {
        log.info("查询待洞察的客群列表，当前时间：{}", DateUtil.date2str(new Date(), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
        List<UserGroupInfo> userGroupInfoList = crowdMapper.queryUserGroupForInsight();
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "查询成功", userGroupInfoList);
    }

    @Override
    public ResultObject<String> downloadUserGroup(String groupId) {
        log.info("洞察客群：{}", groupId);
        HashMap<String, Object> groupInfo = crowdMapper.queryByGroupID(groupId);
        String isStaticCustomer = groupInfo.get("isStaticCustomer").toString();
        if ("1".equals(isStaticCustomer)) {
            return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "当前人群为标签人群，无须同步信息", null);
        }
        int count = Integer.parseInt(redisService.get(REDIS_COUNT_NAME).toString());
        if (count <= MAX_INSIGHT_TIMES) {
            log.info("今日第{}次发起客群洞察", count);
            ThreadPools.asynchronousTask(new Runnable() {
                @Override
                public void run() {
                    // 分别从redis获取客群的uid、手机号、idfa的信息
                    String time = DateUtil.getTimestamp();
                    String phoneFileName = groupId + "_msisdn" + "_" + time + ".txt";
                    Cursor<String> msisdnCursor = redisService.scan(groupId + "-phone");
                    exportFileDataFromRedis.syncExport(msisdnCursor, phoneFileName);

                    // 将文件上传到label_sftp中
                    boolean b = sftpUtils.syncToLabel(phoneFileName);
                    if (!b) {
                        throw new MyException(StatusEnum.ERROR, "上传文件失败");
                    }
                    // 通知TSG获取客群文件
                    Map<String, String> map = new HashMap<>(1);
                    map.put("musicTreeId", groupId);
                    map.put("path", phoneFileName);
                    log.info("洞察通知信息：{}", map);
                    RestHttpPost post = new RestHttpPost();
                    Map<String, String> response = post.doPostNoEncryption(map, LABEL_PREFIX + customerInsight);
                    String code = response.get("code");
                    if (!"200".equals(code)) {
                        throw new MyException(StatusEnum.ERROR, "通知标签平台洞察失败，返回响应码：" + code);
                    }
                    log.info("通知标签平台洞察，返回响应码：{}", code);
                    redisService.add(REDIS_COUNT_NAME, count + 1);;
                }
            });
            return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "成功", "");
        } else {
            log.info("今日洞察次数：{}", count);
            throw new MyException(StatusEnum.ERROR, "当日客群洞察次数已超过20次，请明日再试");
        }
    }

    @Override
    public void resetInsightTimes() {
        redisService.add(REDIS_COUNT_NAME, 1);
        log.info("今日洞察次数剩余{}次", MAX_INSIGHT_TIMES);
    }

    /**
     * 查询人群
     * 
     * @param userGroupDTO
     * @param user
     * @return
     */
    @Override
    public ResultObject<List<UserGroupVo>> queryUserGroupList(UserGroupDTO userGroupDTO, SysUser user) {
        if (null == user) {
            throw new MyException(StatusEnum.TOKEN_WRONG, StatusEnum.TOKEN_WRONG.getMsg());
        }
        List<UserGroupVo> userGroupVos = crowdMapper.queryUserGroupList(userGroupDTO);
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "成功", userGroupVos);
    }

    /**
     * hive是否需要延迟更新
     *
     * @param gid
     * @param json
     */
    private void hiveDelayUpdate(String gid, String json) {
        // JSON转换成对应的JavaBean
        AttributeBean bean = JSON.parseObject(json, AttributeBean.class);
        Map<String, Object> map = new HashMap<>();
        map.put("groupId", gid);
        // 时间类型 1：过去时段 2 ：未来时段 3：过去某天 4：未来某天 5：自定义区间 6：过去时段（周）7:过去某周
        if (StringUtils.isNotBlank(bean.getDateType())) {
            String dateType = bean.getDateType();
            String dayCont = bean.getDayCont();
            // 和过去一天有关，延迟更新：1- 不延迟； 2- 延迟；
            // dayType：1
            // dayType：3 dayCont:1
            // dayType :5 dateEnd:今天的前一天
            if (dateType.equals("1") || (dateType.equals("3") && dayCont.equals("1"))) {
                map.put("delayUpdate", 2);
            } else if (dateType.equals("5")) {
                // dateEnd: 20191209
                String dateEnd = bean.getDateEnd();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DateUtil.DATE_FORMAT_YYYYMMDD);
                Calendar calendar = new GregorianCalendar();
                calendar.setTime(new Date());
                calendar.add(calendar.DATE, -1);
                String yesterday = simpleDateFormat.format(calendar.getTime());
                if (dateEnd.equals(yesterday)) {
                    map.put("delayUpdate", 2);
                }
            } else {
                map.put("delayUpdate", 1);
            }
        } else {
            map.put("delayUpdate", 1);
        }
        crowdMapper.updateHiveDelayUpdateInfo(map);
    }

    /**
     * 将包含静态标签规则的客群，上报至统一标签服务平台
     *
     * @param map
     */
    private void staticCustomerReport(Map<String, Object> map) {
        String groupId = String.valueOf(map.get("groupId"));
        String[] resGroups = String.valueOf(map.get("resGroups")).split(",");
        log.info(String.valueOf(map.get("resGroups")));
        log.info(resGroups[0]);
        log.info(resGroups[1]);
        HashMap<String, Object> left = crowdMapper.queryByGroupID(resGroups[0]);
        HashMap<String, Object> right = crowdMapper.queryByGroupID(resGroups[1]);
        String leftGroupId = String.valueOf(left.get("groupId"));
        String rightGroupId = String.valueOf(left.get("groupId"));
        String leftIsStaticCustomer = String.valueOf(left.get("isStaticCustomer"));
        String rightIsStaticCustomer = String.valueOf(right.get("isStaticCustomer"));
        String leftCreateWay = String.valueOf(left.get("createWay"));
        String rightCreateWay = String.valueOf(right.get("createWay"));
        HashMap<String, Object> leftDynamicCustomer = crowdMapper.dynamicCustomerInfo(leftGroupId);
        HashMap<String, Object> rightDynamicCustomer = crowdMapper.dynamicCustomerInfo(rightGroupId);
        String createBy = String.valueOf(map.get("createBy"));
        int calType = 0;
        switch (createBy) {
            case "4":
                calType = 1;
                break;
            case "5":
                calType = 2;
                break;
            case "6":
                calType = 3;
                break;
            case "7":
                calType = 4;
                break;
            case "8":
                calType = 5;
                break;
        }
        if ("1".equals(leftIsStaticCustomer) || "1".equals(rightIsStaticCustomer)) {
            CustomerMergeRequestBean bean = new CustomerMergeRequestBean();
            bean.setMergeCustomerId(groupId);
            bean.setUserId(String.valueOf(map.get("creatorName")));
            bean.setGroupId("1");
            /**
             * 音乐： 4-交集创建；5-并集创建；6-左差集创建；7-右差集创建；8-对称差集创建； 统一标签： 1-交集；2:并集；3:左差集；4:右差集；5:对称差集；
             */
            bean.setCalType(calType);
            CustomerFileBean customerFileBean_1 = new CustomerFileBean();
            CustomerFileBean customerFileBean_2 = new CustomerFileBean();
            // uid
            if (null == leftDynamicCustomer) {
                customerFileBean_1.setCustomerId(leftGroupId);
                customerFileBean_1.setType(1);
            } else {
                if (null != leftDynamicCustomer.get("uidFileName")) {
                    String fileName = String.valueOf(leftDynamicCustomer.get("uidFileName"));
                    customerFileBean_1.setUidPath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                if (null != leftDynamicCustomer.get("msisdnFileName")) {
                    String fileName = String.valueOf(leftDynamicCustomer.get("msisdnFileName"));
                    customerFileBean_1.setPhonePath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                if (null != leftDynamicCustomer.get("deviceFileName")) {
                    String fileName = String.valueOf(leftDynamicCustomer.get("deviceFileName"));
                    customerFileBean_1.setImeiIdfaPath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                customerFileBean_1.setType(2);
            }

            if (null == rightDynamicCustomer) {
                customerFileBean_2.setCustomerId(rightGroupId);
                customerFileBean_2.setType(1);
            } else {
                if (null != rightDynamicCustomer.get("uidFileName")) {
                    String fileName = String.valueOf(rightDynamicCustomer.get("uidFileName"));
                    customerFileBean_2.setUidPath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                if (null != rightDynamicCustomer.get("msisdnFileName")) {
                    String fileName = String.valueOf(rightDynamicCustomer.get("msisdnFileName"));
                    customerFileBean_2.setPhonePath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                if (null != rightDynamicCustomer.get("deviceFileName")) {
                    String fileName = String.valueOf(rightDynamicCustomer.get("deviceFileName"));
                    customerFileBean_2.setImeiIdfaPath(fileName);
                    sftpUtils.fileSyncToLabel(fileName);
                }
                customerFileBean_2.setType(2);
            }
            log.info("slave_1:{}", customerFileBean_1.toString());
            log.info("slave_2:{}", customerFileBean_2.toString());
            bean.setCustomerFile1(customerFileBean_1);
            bean.setCustomerFile2(customerFileBean_2);
            RestHttpPost post = new RestHttpPost();
            post.doRest(bean, LABEL_PREFIX + CUSTOMER_MERGE);
        }
    }

    /**
     * 客群状态上报
     */
    private void customerStatus(String groupId, int status) {
        CustomerStatusRequestBean bean = new CustomerStatusRequestBean();
        bean.setCustomerId(groupId);
        bean.setStatus(status);
        RestHttpPost post = new RestHttpPost();
        post.doRest(bean, LABEL_PREFIX + CUSTOMER_STATUS);
    }

    /**
     * 预处理需要重组的客群 1、区分是否是静态标签客群- 静态标签客群专属于统一标签服务平台，不需要提供客群明细 2、如果是静态标签客群，即不做处理 3、如果不是静态标签客群，则需要从redis中导出客群明细
     * 4、创建recombine_customer_master/recombine_customer_slave记录
     *
     * @param map
     */
    private boolean recombineCustomerPerHandel(Map<String, Object> map) {
        log.info("预处理重组客群：{}", map.toString());
        String customerID = String.valueOf(map.get("groupId"));
        String[] resGroups = String.valueOf(map.get("resGroups")).split(",");
        String masterGroupId = String.valueOf(resGroups[0]);
        String slaveGroupId = String.valueOf(resGroups[1]);
        HashMap<String, Object> master = crowdMapper.queryByGroupID(masterGroupId);
        HashMap<String, Object> slave = crowdMapper.queryByGroupID(slaveGroupId);
        String masterIsStaticCustomer = String.valueOf(master.get("isStaticCustomer"));
        String slaveIsStaticCustomer = String.valueOf(slave.get("isStaticCustomer"));
        String createBy = String.valueOf(map.get("createBy"));
        int calType = 0;
        switch (createBy) {
            case "4":
                calType = 1;
                break;
            case "5":
                calType = 2;
                break;
            case "6":
                calType = 3;
                break;
            case "7":
                calType = 4;
                break;
            case "8":
                calType = 5;
                break;
        }
        // 两个动态客群由服务云完成重组
        if ("0".equals(masterIsStaticCustomer) && "0".equals(slaveIsStaticCustomer)) {
            log.info("两个动态客群由服务云完成重组");
            return true;
        }
        // 客群状态调整到进行中
        Map<String, Object> updateCrowd = new HashMap<>();
        updateCrowd.put("groupId", customerID);
        updateCrowd.put("createStatus", 4);
        updateCrowd.put("isStaticCustomer", 1);
        crowdMapper.updateCrowd(updateCrowd);
        // 如果两个都是静态客群，则直接上报至统一标签服务平台
        if ("1".equals(masterIsStaticCustomer) && "1".equals(slaveIsStaticCustomer)) {
            log.info("如果两个都是静态客群，则直接上报至统一标签服务平台");
            CustomerMergeRequestBean bean = new CustomerMergeRequestBean();
            bean.setMergeCustomerId(customerID);
            bean.setUserId(String.valueOf(map.get("creatorName")));
            bean.setGroupId("1");
            bean.setCalType(calType);
            CustomerFileBean customerFileBean_1 = new CustomerFileBean();
            CustomerFileBean customerFileBean_2 = new CustomerFileBean();
            customerFileBean_1.setType(1);
            log.info("masterGroupId:{}", masterGroupId);
            customerFileBean_1.setCustomerId(masterGroupId);
            customerFileBean_2.setType(1);
            log.info("slaveGroupId:{}", slaveGroupId);
            customerFileBean_2.setCustomerId(slaveGroupId);
            log.info("slave_1:{}", customerFileBean_1.toString());
            log.info("slave_2:{}", customerFileBean_2.toString());
            bean.setCustomerFile1(customerFileBean_1);
            bean.setCustomerFile2(customerFileBean_2);
            log.info("merge bean:{}", bean.toString());
            doPost(bean);
            return true;
        }
        // 下载主客群明细
        boolean masterDetail = customerDetailDownloadFromRedis(masterGroupId, masterIsStaticCustomer, customerID);
        if (!masterDetail) {
            Map<String, Object> updateMaster = new HashMap<>();
            updateMaster.put("groupId", masterGroupId);
            updateMaster.put("createStatus", 6);
            updateMaster.put("remark", masterGroupId + "下载明细数据失败");
            crowdMapper.updateCrowd(updateMaster);
        }
        // 下载从客群明细
        boolean slaveDetail = customerDetailDownloadFromRedis(slaveGroupId, slaveIsStaticCustomer, customerID);
        if (!slaveDetail) {
            Map<String, Object> updateSlave = new HashMap<>();
            updateSlave.put("groupId", slaveGroupId);
            updateSlave.put("createStatus", 6);
            updateSlave.put("remark", slaveGroupId + "下载明细数据失败");
            crowdMapper.updateCrowd(updateSlave);
        }
        Map<String, Object> recombineCustomerMaster = new HashMap<>();
        recombineCustomerMaster.put("customerId", customerID);
        recombineCustomerMaster.put("userId", map.get("creatorId"));
        recombineCustomerMaster.put("groupId", "1");
        recombineCustomerMaster.put("calType", calType);
        recombineCustomerMaster.put("masterCustomerId", masterGroupId);
        recombineCustomerMaster.put("slaveCustomerId", slaveGroupId);
        log.info("recombineCustomerMaster:{}", recombineCustomerMaster.toString());
        if (crowdMapper.isRecombineCustomerMasterExist(recombineCustomerMaster)) {
            crowdMapper.updateRecombineCustomerMaster(recombineCustomerMaster);
        } else {
            crowdMapper.addRecombineCustomerMaster(recombineCustomerMaster);
        }
        return true;
    }

    /**
     * 从redis中导出客群明细
     *
     * @param customerID
     * @param isStaticCustomer
     * @return
     */
    private boolean customerDetailDownloadFromRedis(String customerID, String isStaticCustomer,
        String masterCustomerID) {
        String time = DateUtil.getTimestamp();
        String deviceFileName = customerID + "_device" + "_" + time + ".txt";
        String uidFileName = customerID + "_uid" + "_" + time + ".txt";
        String msisdnFileName = customerID + "_msisdn" + "_" + time + ".txt";
        if (!"1".equals(isStaticCustomer)) {
            log.info("{}为非静态标签客群，从Redis中下载客群明细", customerID);
            // 导出
            Cursor<String> msisdnCursor = redisService.scan(customerID + "-phone");
            exportFileDataFromRedis.export(msisdnCursor, msisdnFileName);
            Cursor<String> uidCursor = redisService.scan(customerID + "-uid");
            exportFileDataFromRedis.export(uidCursor, uidFileName);
            Cursor<String> deviceCursor = redisService.scan(customerID + "-imei");
            exportFileDataFromRedis.export(deviceCursor, deviceFileName);
        }
        Map<String, Object> recombineCustomerSlave = new HashMap<>();
        recombineCustomerSlave.put("customerId", customerID);
        recombineCustomerSlave.put("masterCustomerId", masterCustomerID);
        if ("1".equals(isStaticCustomer)) {
            recombineCustomerSlave.put("customerType", 1);
        } else {
            recombineCustomerSlave.put("customerType", 2);
            recombineCustomerSlave.put("msisdnFileName", msisdnFileName);
            recombineCustomerSlave.put("uidFileName", uidFileName);
            recombineCustomerSlave.put("deviceFileName", deviceFileName);
        }
        log.info("slave info:{}", recombineCustomerSlave.toString());
        if (crowdMapper.isRecombineCustomerSlaveExist(recombineCustomerSlave)) {
            log.info("exist and update slave");
            crowdMapper.updateRecombineCustomerSlave(recombineCustomerSlave);
        } else {
            log.info("create slave");
            crowdMapper.addRecombineCustomerSlave(recombineCustomerSlave);
        }
        return true;
    }

    /**
     * 上报重组客群信息
     *
     * @param bean
     */
    private void doPost(CustomerMergeRequestBean bean) {
        RestHttpPost post = new RestHttpPost();
        post.doRest(bean, LABEL_PREFIX + CUSTOMER_MERGE);
    }
}
